#ifndef MATLAB_SOLVER_H 
#define MATLAB_SOLVER_H 
#include <map>
#include <string>
#include <engine.h>
 //#include <mex.h>   
namespace CGF{

class MatlabTool 
{
public:
	MatlabTool():matlabEngine(NULL){}
		bool connect_matlab();
		~MatlabTool();

		// set variatble
		template<typename   EIGEN_M> 
		bool  set_variable(const char * name, EIGEN_M &mat)
		{
			return set_variable(std::string(name), mat);
		}

		template<typename   EIGEN_M>  
		bool  set_variable(std::string &name, EIGEN_M &mat);
	 
		//get variatble
		template<typename   EIGEN_M>
		bool get_variable(const char *name, EIGEN_M &m)
		{
			return get_variable(std::string(name), m);
		}
		template<typename   EIGEN_M>
		bool get_variable(std::string &name,EIGEN_M &m);

		bool exe_command(const char *command, bool outPut=false);
		bool exe_command(std::string &command, bool outPut=false);

private:
	 Engine* matlabEngine;
	 std::map<std::string, mxArray*> variables;
};

template<typename   EIGEN_M>
	bool MatlabTool::get_variable(std::string &name, EIGEN_M &m)
	{
			mxArray* var = 	engGetVariable(matlabEngine, name.c_str());
			if(!var)
				return false;
			
			double *data =  (double*)(mxGetData(var));

			for(int i = 0; i < m.size(); i++)
			{
				m.data()[i] = data[i];
			}
			mxDestroyArray(var);
			
			return true;
	}

template<typename   EIGEN_M>
	bool  MatlabTool::set_variable(std::string &name, EIGEN_M &mat)
	{
		 mxArray* var;
		if(variables.count(name)==0)
		{
			var = mxCreateNumericMatrix(mat.rows(), mat.cols(), mxDOUBLE_CLASS, mxREAL);
			variables[name] = var;
		}
		else 		
			var = variables[name];
			
			double *data =  (double*)(mxGetData(var));
			for(int i = 0; i < mat.size(); i++)
			{
					data[i]= mat.data()[i];
			}
			
			return ! engPutVariable(matlabEngine, name.c_str(), var);
	}

class MatlabSparseSolver:public MatlabTool 
{
public:
	MatlabSparseSolver(){}
		
		template<typename   EIGEN_VEC>
		bool solve(const EIGEN_VEC &s_i,const EIGEN_VEC &s_j,
						const EIGEN_VEC &s_val,const EIGEN_VEC &b,
						EIGEN_VEC &x)
		{
				 set_variable("s_i", s_i);
				 set_variable("s_j", s_j);
				 set_variable("s_val", s_val);
				 set_variable("b", b);

				 exe_command("if min(s_i) ==0 s_i = s_i+1; end");
				 exe_command("if min(s_j) ==0 s_j = s_j+1; end");
				
				 exe_command("Ss=sparse(s_i,s_j,s_val);");
				 exe_command("x=mldivide(Ss, b);");
					
				 return get_variable("x", x);
		}
//private:
//	bool  set_sparse_variable(const char * name,const int &m, const int &n,const int &maxValNum);

};
}


#endif
